package zen2d;

import java.awt.*;
import java.util.*;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

public class Zen2d {

    public static int WIDTH = 480;
    public static int HEIGHT = 480;

    private static int x, y = 0;

    private static Window window = new SwingWindow();

    private static CopyOnWriteArrayList<Sprite> sprites;
    private static CopyOnWriteArrayList<KeyEventListener> keyEventListeners;
    private static CopyOnWriteArrayList<MouseEventListener> mouseEventListeners;

    private static LinkedList<Task> tasks;

    public static void createWindow(int x, int y, int width, int height) {

        WIDTH = width;
        HEIGHT = height;

        sprites = new CopyOnWriteArrayList<>();
        keyEventListeners = new CopyOnWriteArrayList<>();
        mouseEventListeners = new CopyOnWriteArrayList<>();
        tasks = new LinkedList<>();

        window.setKeyEventListener(new KeyEventListener() {
            @Override
            public void keyDown(int keyCode) {
                for (KeyEventListener keyEventListener : keyEventListeners) {
                    keyEventListener.keyDown(keyCode);
                }
            }

            @Override
            public void keyUp(int keyCode) {
                for (KeyEventListener keyEventListener : keyEventListeners) {
                    keyEventListener.keyUp(keyCode);
                }
            }
        });
        window.setMouseEventListener(new MouseEventListener() {
            @Override
            public void mousePressed(Point point) {
                for (MouseEventListener mouseEventListener : mouseEventListeners) {
                    mouseEventListener.mousePressed(point);
                }
            }

            @Override
            public void mouseReleased(Point point) {
                for (MouseEventListener mouseEventListener : mouseEventListeners) {
                    mouseEventListener.mouseReleased(point);
                }
            }

            @Override
            public void mouseWheelMoved(int wheelRotation) {
                for (MouseEventListener mouseEventListener : mouseEventListeners) {
                    mouseEventListener.mouseWheelMoved(wheelRotation);
                }
            }

            @Override
            public void mouseDragged(Point point) {
                for (MouseEventListener mouseEventListener : mouseEventListeners) {
                    mouseEventListener.mouseDragged(point);
                }
            }

            @Override
            public void mouseMoved(Point point) {
                for (MouseEventListener mouseEventListener : mouseEventListeners) {
                    mouseEventListener.mouseMoved(point);
                }
            }
        });

        window.createWindow(x, y, WIDTH, HEIGHT);

        new Thread(() -> {
            while (true) {
                try {
                    Thread.sleep(30);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                loop();
            }
        }).start();
    }

    public static void createWindow(int x, int y) {
        createWindow(x, y, WIDTH, HEIGHT);
    }

    public static void createWindow() {
        Dimension screensize = Toolkit.getDefaultToolkit().getScreenSize();
        createWindow(x, y, screensize.width, screensize.height);
//        self.targetFrame.setExtendedState(JFrame.MAXIMIZED_BOTH);
    }


    public static void addSprite(Sprite sprite) {
        sprites.add(sprite);
        keyEventListeners.add(sprite);
    }

    public static void removeSprite(Sprite sprite) {
        sprites.remove(sprite);
        keyEventListeners.remove(sprite);
    }

    public static void addTask(int millis, Function function) {
        tasks.add(new Task(millis, function));
    }


    public static List<Sprite> getCollisionObjects(Sprite sprite) {

        List<Sprite> collisionObjects = new ArrayList<>();

        for (Iterator<Sprite> ite = sprites.iterator(); ite.hasNext(); ) {
            Sprite obj = ite.next();
            if (obj == sprite) {
                continue;
            }
            if (obj.getBounds().intersects(sprite.getBounds())) {
                collisionObjects.add(obj);
            }
        }
        return collisionObjects;
    }

    public static <T> T getCollisionWithClass(Sprite sprite, Class<T> cls) {

        T collisionObject = null;
        List<Sprite> collisionObjects = getCollisionObjects(sprite);

        for (Iterator<Sprite> ite = collisionObjects.iterator(); ite.hasNext(); ) {
            Sprite obj = ite.next();
            if (obj.getClass().equals(cls)) {
                collisionObject = (T) obj;
            }
        }
        return collisionObject;
    }


    private static void update() {

        for (Iterator<Sprite> ite = sprites.iterator(); ite.hasNext(); ) {
            Sprite sprite = ite.next();
            sprite.update();
        }
    }

    private static void executeTask() {

        for (Iterator<Task> iterator = tasks.iterator(); iterator.hasNext(); ) {
            Task task = iterator.next();
            if (task.execute()) {
                iterator.remove();
            }
        }

    }


    public void clearRect(int x, int y, int width, int height) {
        window.clearRect(x, y, width, height);
    }

    private static void render() {

        window.clearRect(0, 0, WIDTH, HEIGHT);

        /**
         * 根据y轴大小设置覆盖顺序
         */
        if (isAngle()) {

            Collections.sort(sprites, (o1, o2) -> {
                int diff = o1.getLocation().y - o2.getLocation().y;
                if (diff > 0) {
                    return 1;
                } else if (diff < 0) {
                    return -1;
                }
                return 0;
            });
        }

        for (Iterator<Sprite> ite = sprites.iterator(); ite.hasNext(); ) {
            Sprite sprite = ite.next();
            sprite.draw(window.getGraphicsContext());
        }

        window.repaint();
    }

    private static void loop() {

        update();
        executeTask();
        render();
    }

    /**
     * 是否为倾斜角度（按y轴大小设置顺序） ，默认为平面角度
     */
    private static boolean angle = false;

    public static boolean isAngle() {
        return angle;
    }

    public static void setAngle(boolean angle) {
        Zen2d.angle = angle;
    }

    public static boolean isHighQuality() {
        return window.isHighQuality();
    }

    public static void setHighQuality(boolean highQuality) {
        window.setHighQuality(highQuality);
    }


    public static void moveViewport(int offsetX, int offsetY) {
        window.moveViewport(offsetX, offsetY);
    }

    public static int getViewportX() {
        return window.getViewportX();
    }

    public static int getViewportY() {
        return window.getViewportY();
    }

    public static void setTitle(String title) {
        window.setTitle(title);
    }

    public static void showMsg(String msg) {
        window.showMsg(msg);
    }
}
